<html>
    <head>
        <title>发布本地事件</title>
    </head>
    <body>
        <script>
             /*
                        一、发布本地事件

                                有两种方式发布本地事件：

                                    1、使用  ILocalEventBus 服务发布事件：

                                                eg:  当产品的库存计数发生变化时，发布本地事件。

                                                        using System;
                                                        using System.Threading.Tasks;
                                                        using Volo.Abp.DependencyInjection;
                                                        using Volo.Abp.EventBus.Local;

                                                        namespace AbpDemo
                                                        {
                                                            public class MyService : ITransientDependency
                                                            {
                                                                private readonly ILocalEventBus _localEventBus;

                                                                public MyService(ILocalEventBus localEventBus)
                                                                {
                                                                    _localEventBus = localEventBus; // 注入本地事件总线服务
                                                                }
                                                                
                                                                public virtual async Task ChangeStockCountAsync(Guid productId, int newCount)
                                                                {
                                                                    // 实现你的逻辑
                                                                    
                                                                    // 发布事件
                                                                    await _localEventBus.PublishAsync(
                                                                        new StockCountChangedEvent  // 事件类型
                                                                        {
                                                                            ProductId = productId,
                                                                            NewCount = newCount
                                                                        }
                                                                    );
                                                                }
                                                            }
                                                        }  

                                                PublishAsync 方法获取一个参数： 事件对象，它负责保存与事件相关的数据。 它是一个简单的普通类：

                                                        using System;

                                                        namespace AbpDemo
                                                        {
                                                            public class StockCountChangedEvent
                                                            {
                                                                public Guid ProductId { get; set; }
                                                                
                                                                public int NewCount { get; set; }
                                                            }
                                                        }

                                                即使你不需要传递任何事件数据，你也需要创建一个事件类。 （这种情况下是一个空类）


                                   2、在 "实体" 或 "聚合根"类中发布事件

                                                实体不能通过依赖注入服务，但是在实体/聚合根类中发布本地事件是很常见的。

                                                    eg: 在聚合根方法中发布本地事件：
                                                        using System;
                                                        using Volo.Abp.Domain.Entities;

                                                        namespace AbpDemo
                                                        {
                                                            public class Product : AggregateRoot<Guid>
                                                            {
                                                                public string Name { get; set; }
                                                                
                                                                public int StockCount { get; private set; }

                                                                private Product() { }

                                                                public Product(Guid id, string name)
                                                                    : base(id)
                                                                {
                                                                    Name = name;
                                                                }

                                                                public void ChangeStockCount(int newCount)
                                                                {
                                                                    StockCount = newCount;
                                                                    
                                                                    // 发布本事件
                                                                    AddLocalEvent(
                                                                        new StockCountChangedEvent // 事件对象
                                                                        {
                                                                            ProductId = Id,
                                                                            NewCount = newCount
                                                                        }
                                                                    );
                                                                }
                                                            }
                                                        }
                                                AggregateRoot类定义AddLocalEvent以添加新的本地事件，该事件在聚合根对象保存（创建、更新或删除）到数据库时发布。
                                                
                                        (提示：如果实体发布了这样的事件，最好以受控方式更改相关属性，就像上面的示例，--StockCount只能通过发布事件的 ChangeStockCount方法进行修改)




                                        ★、IGeneratesDomainEvents 接口 

                                                实际上，添加本地事件方法 AddLocalEvent 不是 AggregateRoot 类独有的。你可以为任何实体类实现 IGeneratesDomainEvents 接口。

                                                    但是。 AggregateRoot 类默认实现它，让你轻松。

                                                    不建议为非聚合根的实体实现此接口，因为它可能不适用此类实体的某些数据库提供程序。 它适用于EF Core，单不适用用 MongoDB。！！



                                        ★、它是如何实施的？

                                                调用 AddLocalEvent 不会立即发布事件。当你将更改保存到数据库时，事件才会发布：

                                                        ①、对于EF Core，它发布在DbContext.SaveChanges上。

                                                        ②、对于MongoDB，当你调用存储库的InsertAsync、UpdateAsync或DeleteAsync方法时会发布它（因为MongoDB没有更改跟踪系统）。
                    */
        </script>
    </body>
</html>